home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #5 / Amiga Plus CD - 2000 - No. 5.iso / Tools / Dev / Real / dither.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  8KB  |  309 lines

  1. /*
  2.  * Copyright (c) 1997 Miloslaw Smyk
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *      This product includes software developed by Miloslaw Smyk
  16.  * 4. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. #define REVISION "40.2"
  32. #define AUTHOR   "Miloslaw Smyk"
  33. #define VERNUM   40
  34. #define REVNUM   2
  35.  
  36. #define DT_FS                0
  37. #define DT_ORDERED    1
  38. #define DT_NONE            2
  39.  
  40. /* some useful includes */
  41.  
  42. #include <string.h>
  43.  
  44. int dither_type = DT_NONE;
  45.  
  46. struct R3DHandle
  47. {
  48.     UBYTE depth;
  49.     UWORD size_x, size_y;
  50.     SHORT *line;
  51.     int line_width;
  52. };
  53.  
  54.  
  55. /*
  56. ** 4x4 4-bit dispersed dot ordered dither pattern, which is the base
  57. ** for final dither pattern, calculated as soon as screen depth
  58. ** is known.
  59. */
  60.  
  61. const UBYTE dithBase[4][4] = {
  62.     1, 15,  2, 12,
  63.     9,  5, 10,  7,
  64.     3, 13,  0, 14,
  65.    11,  7,  8,  4
  66. };
  67.  
  68. static struct dith
  69. {
  70.     UBYTE r, g, b, g2;
  71. } dith[4][4];
  72.  
  73. struct dither_val
  74. {
  75.     UBYTE r[2], g[2], b[2], g2[2];
  76. }    dither[256];
  77.  
  78. int red5[256], green5[256], blue5[256], green6[256];
  79.  
  80. enum {COL_ORIGINAL, COL_SHIFTED};
  81.  
  82. /* macros we use to get fractions with integer math */
  83. #define SCALING_FACTOR    4
  84. #define HALF    8
  85. #define DESCALE(expr) (((expr) + HALF) >> SCALING_FACTOR)
  86.  
  87.  
  88. void LIBInitDithering(void)
  89. {
  90.     int i,j;
  91.  
  92.     /* calculate errors for every possible pixel value. */
  93.     for(i = 0; i < 256; i++)
  94.     {
  95.         red5[i] = i - ((i + 4) & ~0x07);
  96.         green5[i] = i - ((i + 4) & ~0x07);
  97.         green6[i] = i - ((i + 2) & ~0x03);
  98.         blue5[i] = i - ((i + 4) & ~0x07);
  99.     }
  100.  
  101.     for(i = 0; i < 256; i++)
  102.     {
  103.         dither[i].r[COL_ORIGINAL] = i & ~0x07;
  104.         dither[i].g[COL_ORIGINAL] = i & ~0x07;
  105.         dither[i].g2[COL_ORIGINAL] = i & ~0x03;
  106.         dither[i].b[COL_ORIGINAL] = i & ~0x07;
  107.  
  108.         dither[i].r[COL_SHIFTED] = MIN(i + 8, 255);
  109.         dither[i].g[COL_SHIFTED] = MIN (i + 8, 255);
  110.         dither[i].g2[COL_SHIFTED] = MIN(i + 4,255);
  111.         dither[i].b[COL_SHIFTED] = MIN(i + 8, 255);
  112.     }
  113.  
  114.     for(j = 0; j < 4; j++)
  115.         for(i = 0; i < 4; i++)
  116.         {
  117.             dith[i][j].r = (dithBase[i][j] * 16) / 32;
  118.             dith[i][j].g = (dithBase[i][j] * 16) / 32;
  119.             dith[i][j].g2 = (dithBase[i][j] * 16) / 64;
  120.             dith[i][j].b = (dithBase[i][j] * 16) / 32;
  121.         }
  122. }
  123.  
  124. void LIBDitherLine(struct R3DHandle *handle, UBYTE *buf, int len, int x, int y)
  125. {
  126.     int i;
  127.     int bsame_r, bnext_r, next_r;        
  128.     int bsame_g, bnext_g, next_g;        
  129.     int bsame_b, bnext_b, next_b;        
  130.     UBYTE *inptr;
  131.     SHORT *errptr;
  132.     int delta;
  133.     int temp;
  134.  
  135.     if(handle->depth == 15 || handle->depth == 16)
  136.     {
  137.         switch(dither_type)
  138.         {
  139.             case DT_FS:
  140.                 if(handle->line_width != len)
  141.                 {
  142.                     if(handle->line)
  143.                         FreeVec(handle->line);
  144.  
  145.                     handle->line = AllocVec(sizeof(SHORT) * (len + 2) * 3, MEMF_ANY | MEMF_CLEAR);
  146.                     handle->line_width = len;
  147.                 }
  148.  
  149.                 inptr = buf;
  150.                 errptr = handle->line + 3;
  151.  
  152.                 /* make sure there is no error at the start of the line */
  153.                 for(i = 0; i < 3; i++)
  154.                     errptr[i] = 0;
  155.  
  156.                 bsame_r = bnext_r = next_r = 0;
  157.                 bsame_g = bnext_g = next_g = 0;
  158.                 bsame_b = bnext_b = next_b = 0;
  159.  
  160.                 for(i = 0; i < len; i++)
  161.                 {
  162.                     /* red component */
  163.  
  164.                     temp = *inptr + DESCALE(next_r + bsame_r);
  165.  
  166.                     if(temp < 0)
  167.                         *inptr = 0;
  168.                     else
  169.                         if(temp > 255)
  170.                             *inptr = 255;
  171.                         else
  172.                             *inptr = temp;
  173.  
  174.                     /* right-down pixel gets 1/16 of error */
  175.                     bnext_r = red5[*inptr];
  176.                     delta = bnext_r << 1;
  177.  
  178.                     /* left-down pixel gets 3/16 of error */
  179.                     next_r = bnext_r + delta;
  180.                     *(errptr - 3) += next_r;
  181.  
  182.                     /* pixel below gets 5/16 of error */
  183.                     next_r += delta;
  184.                     *errptr += next_r;
  185.  
  186.                     /* next pixel (to the right) gets 7/16 of error */
  187.                     next_r += delta;
  188.  
  189.                     /* try to get closest match with color-gun */
  190.                     if(*inptr < 252)
  191.                         *inptr += 4;
  192.  
  193.                     bsame_r = *(errptr);
  194.                     *(errptr) = bnext_r;
  195.                     errptr++;
  196.                     inptr++;
  197.  
  198.                     /* green component */
  199.  
  200.                     temp = *inptr + DESCALE(next_g + bsame_g);
  201.  
  202.                     if(temp < 0)
  203.                         *inptr = 0;
  204.                     else
  205.                         if(temp > 255)
  206.                             *inptr = 255;
  207.                         else
  208.                             *inptr = temp;
  209.  
  210.                     /* right-down pixel gets 1/16 of error */
  211.                     bnext_g = handle->depth == 15 ? green5[*inptr] : green6[*inptr];
  212.                     delta = bnext_g << 1;
  213.  
  214.                     /* left-down pixel gets 3/16 of error */
  215.                     next_g = bnext_g + delta;
  216.                     *(errptr - 3) += next_g;
  217.  
  218.                     /* pixel below gets 5/16 of error */
  219.                     next_g += delta;
  220.                     *errptr += next_g;
  221.  
  222.                     /* next pixel (to the right) gets 7/16 of error */
  223.                     next_g += delta;
  224.  
  225.                     /* try to get closest match with color-gun */
  226.                     if(handle->depth == 15)
  227.                     {
  228.                         if(*inptr < 252)
  229.                             *inptr += 4;
  230.                     }
  231.                     else
  232.                     {
  233.                     if(*inptr < 254)
  234.                         *inptr += 2;
  235.                     }
  236.  
  237.                     bsame_g = *(errptr);
  238.                     *(errptr) = bnext_g;
  239.                     errptr++;
  240.                     inptr++;
  241.  
  242.                     /* blue component */
  243.  
  244.                     temp = *inptr + DESCALE(next_b + bsame_b);
  245.  
  246.                     if(temp < 0)
  247.                         *inptr = 0;
  248.                     else
  249.                         if(temp > 255)
  250.                             *inptr = 255;
  251.                         else
  252.                             *inptr = temp;
  253.  
  254.                     /* right-down pixel gets 1/16 of error */
  255.                     bnext_b = blue5[*inptr];
  256.                     delta = bnext_b << 1;
  257.  
  258.                     /* left-down pixel gets 3/16 of error */
  259.                     next_b = bnext_b + delta;
  260.                     *(errptr - 3) += next_b;
  261.  
  262.                     /* pixel below gets 5/16 of error */
  263.                     next_b += delta;
  264.                     *errptr += next_b;
  265.  
  266.                     /* next pixel (to the right) gets 7/16 of error */
  267.                     next_b += delta;
  268.  
  269.                     /* try to get closest match with color-gun */
  270.                     if(*inptr < 252)
  271.                         *inptr += 4;
  272.  
  273.                     bsame_b = *(errptr);
  274.                     *(errptr) = bnext_b;
  275.  
  276.                     errptr++;
  277.  
  278.                     /* advance input pointer */
  279.                     inptr += 2;
  280.                 }
  281.  
  282.                 break;
  283.  
  284.             case DT_ORDERED:
  285.                 if(handle->depth == 15)
  286.                     for(i = 0; i < len * 4; i += 4)
  287.                     {
  288.                         if(buf[i] - dither[buf[i]].r[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].r)
  289.                             buf[i] = dither[buf[i]].r[COL_SHIFTED];
  290.                         if(buf[i + 1] - dither[buf[i + 1]].g[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].g)
  291.                             buf[i + 1] = dither[buf[i + 1]].g[COL_SHIFTED];
  292.                         if(buf[i + 2] - dither[buf[i + 2]].b[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].b)
  293.                             buf[i + 2] = dither[buf[i + 2]].b[COL_SHIFTED];
  294.                     }
  295.                 else
  296.                     for(i = 0; i < len * 4; i += 4)
  297.                     {
  298.                         if(buf[i] - dither[buf[i]].r[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].r)
  299.                             buf[i] = dither[buf[i]].r[COL_SHIFTED];
  300.                         if(buf[i + 1] - dither[buf[i + 1]].g2[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].g2)
  301.                             buf[i + 1] = dither[buf[i + 1]].g2[COL_SHIFTED];
  302.                         if(buf[i + 2] - dither[buf[i + 2]].b[COL_ORIGINAL] > dith[y & 3][(i / 4) & 3].b)
  303.                             buf[i + 2] = dither[buf[i + 2]].b[COL_SHIFTED];
  304.                     }
  305.                 break;
  306.         }
  307.     }
  308. }
  309.